using System.Linq.Dynamic.Core;
using Ln.Fram.Ddd.Application.Contracts;
using Ln.Fram.SqlSugarCore.Abstractions;
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using SqlSugar;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;

namespace Ln.Fram.Ddd.Application;

public abstract class AbstractReadService<TEntity, TEntityDto, TKey>(ISqlSugarRepository<TEntity> repository)
	: AbstractReadService<TEntity, TEntityDto, TKey, PagedAndSortedResultRequestDto>(repository)
	where TEntity : class, IEntity, new()
{
}

public abstract class
	AbstractReadService<TEntity, TEntityDto, TKey, TGetListInput>(ISqlSugarRepository<TEntity> repository)
	: AbstractReadService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput>(repository)
	where TEntity : class, IEntity, new()
{
}

public abstract class
	AbstractReadService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput>(
		ISqlSugarRepository<TEntity> repository) : ApplicationService,
	IReadOnlyAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput>
	where TEntity : class, IEntity, new()
{
	#region 成员属性
	protected ISqlSugarRepository<TEntity> Repository { get; } = repository;
	protected virtual string? GetPolicyName { get; } = null;
	protected virtual string? GetListPolicyName { get; } = null;
	#endregion

	#region 重写方法
	/// <summary>
	/// 单查按主键
	/// </summary>
	/// <param name="id">主键</param>
	/// <returns>查询结果</returns>
	public virtual async Task<TGetOutputDto> GetAsync(TKey id)
	{
		await CheckPolicyAsync(GetPolicyName);
		return await MapToGetOutputDtoAsync(await GetEntityByIdAsync(id));
	}

	/// <summary>
	/// 多查按条件
	/// </summary>
	/// <param name="input">条件信息</param>
	/// <returns>查询结果</returns>
	public virtual async Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input)
	{
		await CheckPolicyAsync(GetListPolicyName);
		List<TEntity>? entities = null;
		RefAsync<int> totalCount = 0;
		var queryable = CreateFilteredQueryAsync(input);
		if (input is IPagedResultRequest pagedInput)
		{
			entities = await queryable.ToPageListAsync(pagedInput.SkipCount, pagedInput.MaxResultCount, totalCount);
		}
		else
		{
			entities = await queryable.ToListAsync();
			totalCount = entities.Count;
		}
		return new PagedResultDto<TGetListOutputDto>(totalCount, await MapToGetListOutputDtosAsync(entities));
	}

	/// <summary>
	/// 查询按条件
	/// </summary>
	/// <param name="id"></param>
	/// <returns></returns>
	protected abstract Task<TEntity> GetEntityByIdAsync(TKey id);

	/// <summary>
	/// 创建多查筛选条件
	/// </summary>
	/// <param name="input">条件信息</param>
	/// <returns>查询条件</returns>
	protected virtual ISugarQueryable<TEntity> CreateFilteredQueryAsync(TGetListInput input)
	{
		var queryable = Repository._DbQueryable;
		if (input is IPagedAllResultRequestDto allInput && typeof(TEntity).IsAssignableTo(typeof(IHasCreationTime)))
			queryable.WhereIF(allInput.StartTime is not null, x => (x as IHasCreationTime).CreationTime >= allInput.StartTime)
				.WhereIF(allInput.EndTime != null,
					x => (x as IHasCreationTime).CreationTime <= allInput.EndTime.Value.AddDays(1));
		return queryable;
	}

	/// <summary>
	/// 对象映射，从Entity到单查Dto
	/// </summary>
	/// <param name="entity">Entity实体</param>
	/// <returns>单查Dto</returns>
	protected virtual Task<TGetOutputDto> MapToGetOutputDtoAsync(TEntity entity)
	{
		return Task.FromResult(ObjectMapper.Map<TEntity, TGetOutputDto>(entity));
	}

	/// <summary>
	/// 对象映射，从Entity到多查Dto
	/// </summary>
	/// <param name="entity">Entity实体</param>
	/// <returns>多查Dto</returns>
	protected virtual Task<TGetListOutputDto> MapToGetListOutputDtoAsync(TEntity entity)
	{
		return Task.FromResult(ObjectMapper.Map<TEntity, TGetListOutputDto>(entity));
	}

	/// <summary>
	/// 对象列表映射，从Entity到多查Dto
	/// </summary>
	/// <param name="entities">Entity实体列表</param>
	/// <returns>多查Dto列表</returns>
	protected virtual async Task<List<TGetListOutputDto>> MapToGetListOutputDtosAsync(List<TEntity> entities)
	{
		var dtos = new List<TGetListOutputDto>();
		foreach (var entity in entities)
			dtos.Add(await MapToGetListOutputDtoAsync(entity));
		return dtos;
	}
	#endregion

	#region 自身方法
	/// <summary>
	/// 导出为Excel文件
	/// </summary>
	/// <param name="input">查询条件</param>
	/// <returns>Excel文件流</returns>
	public async Task<IActionResult> GetExportExcelAsync(TGetListInput input)
	{
		if (input is IPagedResultRequest paged)
		{
			paged.SkipCount = 0;
			paged.MaxResultCount = LimitedResultRequestDto.MaxMaxResultCount;
		}
		var output = await GetListAsync(input);
		var dirPath = $"/wwwroot/temp";
		var fileName = $"{typeof(TEntity).Name}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}_{Guid.NewGuid()}";
		var filePath = $"{dirPath}/{fileName}.xlsx";
		if (!Directory.Exists(dirPath))
			Directory.CreateDirectory(dirPath);
		MiniExcel.SaveAs(filePath, output.Items);
		return new PhysicalFileResult(filePath, "application/vnd.ms-excel");
	}
	#endregion
}